//===- XtensaOperands.td - Xtensa instruction operands -------*- tblgen-*--===//
//
//                     The LLVM Compiler Infrastructure
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

// Immediate operands with a shared generic render method.
class ImmAsmOperand<string name> : AsmOperandClass {
  let Name = name;
  let RenderMethod = "addImmOperands";
  let DiagnosticType = !strconcat("Invalid", name);
}

class Immediate<ValueType vt, code pred, string asmop>
  : Operand<vt>, ImmLeaf<vt, pred> {
  let PrintMethod = "print"#asmop;
  let ParserMatchClass = !cast<AsmOperandClass>(asmop);
}

// imm8 predicate - Immediate in the range [-128,127]
def Imm8_AsmOperand : ImmAsmOperand<"Imm8">;
def imm8 : Immediate<i32, [{ return Imm >= -128 && Imm <= 127; }], "Imm8_AsmOperand"> {
  let EncoderMethod = "getImm8OpValue";
  let DecoderMethod = "decodeImm8Operand";
}

// imm8_sh8 predicate - Immediate in the range [-32768,32512] with (bits[7-0] == 0)
// imm8 value left shifted by 8 bits
def Imm8_sh8_AsmOperand : ImmAsmOperand<"Imm8_sh8">;
def imm8_sh8 : Immediate<i32, [{ return Imm >= -32768 && Imm <= 32512 && ((Imm & 0xFF) == 0); }],
                        "Imm8_sh8_AsmOperand"> {
  let EncoderMethod = "getImm8_sh8OpValue";
  let DecoderMethod = "decodeImm8_sh8Operand";
}

// imm12 predicate - Immediate in the range [-2048,2047]
def Imm12_AsmOperand : ImmAsmOperand<"Imm12">;
def imm12 : Immediate<i32, [{ return Imm >= -2048 && Imm <= 2047; }], "Imm12_AsmOperand"> {
  let EncoderMethod = "getImm12OpValue";
  let DecoderMethod = "decodeImm12Operand";
}

// imm12m predicate - Immediate for MOV operation
def Imm12m_AsmOperand : ImmAsmOperand<"Imm12m">;
def imm12m : Immediate<i32, [{ return Imm >= -2048 && Imm <= 2047; }], "Imm12m_AsmOperand"> {
  let EncoderMethod = "getImm12OpValue";
  let DecoderMethod = "decodeImm12Operand";
}

// uimm4 predicate - Immediate in the range [0,15]
def Uimm4_AsmOperand : ImmAsmOperand<"Uimm4">;
def uimm4 : Immediate<i32, [{ return Imm >= 0 && Imm <= 15; }], "Uimm4_AsmOperand"> {
  let EncoderMethod = "getUimm4OpValue";
  let DecoderMethod = "decodeUimm4Operand";
}

// uimm5 predicate - Immediate in the range [0,31]
def Uimm5_AsmOperand : ImmAsmOperand<"Uimm5">;
def uimm5 : Immediate<i32, [{ return Imm >= 0 && Imm <= 31; }], "Uimm5_AsmOperand"> {
  let EncoderMethod = "getUimm5OpValue";
  let DecoderMethod = "decodeUimm5Operand";
}

// imm1_16 predicate - Immediate in the range [1,16]
def Imm1_16_AsmOperand : ImmAsmOperand<"Imm1_16">;
def imm1_16 : Immediate<i32, [{ return Imm >= 1 && Imm <= 16; }], "Imm1_16_AsmOperand"> {
  let EncoderMethod = "getImm1_16OpValue";
  let DecoderMethod = "decodeImm1_16Operand";
}

// shimm1_31 predicate - Immediate in the range [1,31]
def Shimm1_31_AsmOperand : ImmAsmOperand<"Shimm1_31">;
def shimm1_31 : Immediate<i32, [{ return Imm >= 1 && Imm <= 31; }], "Shimm1_31_AsmOperand"> {
  let EncoderMethod = "getShimm1_31OpValue";
  let DecoderMethod = "decodeShimm1_31Operand";
}

// Memory offset 0..255 for 8-bit memory accesses
def Offset8m8_AsmOperand : ImmAsmOperand<"Offset8m8">;
def offset8m8 : Immediate<i32,
    [{ return Imm >= 0 && Imm <= 255; }],
    "Offset8m8_AsmOperand">;

// Memory offset 0..510 for 16-bit memory accesses
def Offset8m16_AsmOperand : ImmAsmOperand<"Offset8m16">;
def offset8m16 : Immediate<i32,
    [{ return Imm >= 0 && Imm <= 510 && (Imm & 0x1 == 0); }],
    "Offset8m16_AsmOperand">;

// Memory offset 0..1020 for 32-bit memory accesses
def Offset8m32_AsmOperand : ImmAsmOperand<"Offset8m32">;
def offset8m32 : Immediate<i32,
    [{ return Imm >= 0 && Imm <= 1020 && (Imm & 0x3 == 0); }],
    "Offset8m32_AsmOperand">;

// Memory offset 0..60 for 32-bit memory accesses
def Offset4m32_AsmOperand : ImmAsmOperand<"Offset4m32">;
def offset4m32 : Immediate<i32,
    [{ return Imm >= 0 && Imm <= 60 && (Imm & 0x3 == 0); }],
    "Offset4m32_AsmOperand">;

// b4const predicate - Branch Immediate 4-bit signed operand
def B4const_AsmOperand: ImmAsmOperand<"B4const">;
def b4const: Immediate<i32,
  [{ switch (Imm) {
        case -1: case 1: case 2: case 3:  case 4:
        case 5:  case 6: case 7: case 8: case 10: case 12:
        case 16: case 32: case 64: case 128: case 256: return 1;
        default: return 0;
     }
  }],
  "B4const_AsmOperand"> {
  let EncoderMethod = "getB4constOpValue";
  let DecoderMethod = "decodeB4constOperand";
}

// b4constu predicate - Branch Immediate 4-bit unsigned operand
def B4constu_AsmOperand: ImmAsmOperand<"B4constu">;
def b4constu: Immediate<i32,
  [{ switch (Imm) {
        case 32768: case 65536: case 2: case 3:  case 4:
        case 5:  case 6: case 7: case 8: case 10: case 12:
        case 16: case 32: case 64: case 128: case 256: return 1;
        default: return 0;
     }
  }],
  "B4constu_AsmOperand"> {
  let EncoderMethod = "getB4constuOpValue";
  let DecoderMethod = "decodeB4constuOperand";
}
//===----------------------------------------------------------------------===//
// Memory address operands
//===----------------------------------------------------------------------===//

class mem<Operand offset> : Operand<i32> {
  let MIOperandInfo = (ops AR, offset);
  let EncoderMethod = "getMemRegEncoding";
  let OperandType = "OPERAND_MEMORY";
  let PrintMethod = "printMemOperand";
}

def mem8   : mem<offset8m8> {
  let DecoderMethod = "decodeMem8Operand";
}

def mem16  : mem<offset8m16> {
  let DecoderMethod = "decodeMem16Operand";
}

def mem32  : mem<offset8m32> {
  let DecoderMethod = "decodeMem32Operand";
}

def mem32n : mem<offset4m32> {
  let DecoderMethod = "decodeMem32nOperand";
}

//Add patterns for future use in stack addressing mode
def addr_ish1 : ComplexPattern<iPTR, 2, "selectMemRegAddrISH1", [frameindex]>;
def addr_ish2 : ComplexPattern<iPTR, 2, "selectMemRegAddrISH2", [frameindex]>;
def addr_ish4 : ComplexPattern<iPTR, 2, "selectMemRegAddrISH4", [frameindex]>;

//===----------------------------------------------------------------------===//
// Symbolic address operands
//===----------------------------------------------------------------------===//
def XtensaPCRelTargetAsmOperand : AsmOperandClass {
  let Name = "PCRelTarget";
  let ParserMethod = "parsePCRelTarget";
  let PredicateMethod = "isImm";
  let RenderMethod = "addImmOperands";
}

def  pcrel32call : Operand<iPTR> {
  let PrintMethod = "printCallOperand";
  let EncoderMethod = "getCallEncoding";
  let DecoderMethod = "decodeCallOperand";
  let ParserMatchClass = XtensaPCRelTargetAsmOperand;
}

def brtarget : Operand<OtherVT> {
  let PrintMethod = "printBranchTarget";
  let EncoderMethod = "getBranchTargetEncoding";
  let DecoderMethod = "decodeBranchOperand";
  let ParserMatchClass = XtensaPCRelTargetAsmOperand;
}

def jumptarget : Operand<OtherVT> {
  let PrintMethod = "printJumpTarget";
  let EncoderMethod = "getJumpTargetEncoding";
  let DecoderMethod = "decodeJumpOperand";
  let ParserMatchClass = XtensaPCRelTargetAsmOperand;
}

def L32Rtarget : Operand<OtherVT> {
  let PrintMethod = "printL32RTarget";
  let EncoderMethod = "getL32RTargetEncoding";
  let DecoderMethod = "decodeL32ROperand";
  let ParserMatchClass = XtensaPCRelTargetAsmOperand;
}
